home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * *
- * ZIP Processing Functions *
- * These routines are used to process files with the ZIP entension. *
- **************************************************************************/
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- #undef MAIN
-
- #include "fff.h"
- #include "zip.h"
- #include "queue.h"
-
- int Match (char *Str, char *Pat);
- void PrtVerbose (char *Path, char *Name, DOS_FILE_TIME *Time, DOS_FILE_DATE *Date,
- long Size);
- void ChkPage (void);
- int SearchQ (char *Str);
-
- /***********************************************************************
- * DoZip is the main routine to process an entire ZIP file *
- ***********************************************************************/
-
- void
- DoZip (char *Name) {
- FILE *ZIPFile;
-
- if ( (ZIPFile = fopen(Name, "rb")) == NULL ) {
- fprintf(stderr, "%s", Name);
- perror("");
- }
- ProcessHeaders(ZIPFile, Name);
- fclose(ZIPFile);
- }
-
- /***********************************************************************
- * Unlike the other PC-based archivers, PKZip produces files that have *
- * both a distributed directory and a central directory. For programs *
- * such as FFF which are not interested in the content of the files in *
- * the ZIP but in their directory data, a great deal of time can be *
- * saved by processing the central directory rather than reading the *
- * entire file just to find the entries in the distributed directory! *
- * The central directory of a ZIP file is located at the "back end" of *
- * the file, however, finding it it slightly complicate by the fact *
- * the file may have a variable number of non-relevant characters *
- * appended by some of the file transfer protocols (one main-frame *
- * Kermit protocol can append as many as 1,440 non-relevant characters *
- ***********************************************************************/
-
- void
- ProcessHeaders (FILE *ZIPFile, char *Path) {
- extern int TotalMatch, VerboseSwt, CaseSwt, Spaced, PageSwt;
- extern char V_Name[14];
- extern char V_Path[66];
- extern ARC_TYPE ArcType;
- extern int Lnno;
- extern S[6][3];
-
- int i, Printed, Index, ZipLen;
- long FileLen;
- char *Buffer, *Name, *p;
- char DireName[65];
- unsigned Count;
- long Offset, S_Offset, Block;
- unsigned long *Ptr;
- unsigned long CentralSig;
- END_CENTRAL_DIRECTORY_RECORD *EndPtr;
- CENTRAL_DIRECTORY_FILE_HEADER *CentralHeader;
-
- /*----------------------------------------------------------------------*/
- /* Establish the buffer to search the "back end" of the file. */
- /* SEARCH_SIZE (#defined in zip.h) establishes the buffer size and */
- /* should be no less than 1024 bytes. I have found 2048 to be a little */
- /* more sure. */
-
- if ( (Buffer = malloc(SEARCH_SIZE)) == NULL) {
- fprintf(stderr, "Insufficient memory!\n");
- exit(1);
- }
-
- /* Position to the end of the ZIP file and get the file size in bytes */
-
- fseek(ZIPFile, 0L, SEEK_END);
- FileLen = ftell(ZIPFile);
-
- /* Reset the ZIP file position to the beginning of the file */
-
- fseek(ZIPFile, 0L, SEEK_SET);
- if (FileLen < SEARCH_SIZE) {
- ZipLen = fread(Buffer, (size_t) 1, (size_t) FileLen, ZIPFile);
- }
- else {
- fseek(ZIPFile, (long) -SEARCH_SIZE, SEEK_END);
- ZipLen = fread(Buffer, 1, SEARCH_SIZE, ZIPFile);
- }
-
- /* Search backwards for the "End of Central Directory" entry */
-
- for (i = ZipLen - 4; i >= 0; --i) {
- Ptr = (unsigned long *) &Buffer[i];
- if (*Ptr == END_CENTRAL_DIR_SIGNATURE) break;
- }
- if (i < 0) {
- fprintf(stderr, "%s: Invalid ZIP format\n", Path);
- fprintf(stderr, " - No \"End-of-Central-Directory\" record!\n");
- free(Buffer);
- return;
- }
-
- /* The "End of Central Directory" entry contains the count of the entries */
- /* and the offset of the first entry in the Central Directory */
-
- EndPtr = (END_CENTRAL_DIRECTORY_RECORD *) &Buffer[i + 4];
- Count = EndPtr->CentralDirEntries_ThisDisk;
- S_Offset = Offset = EndPtr->OffsetStartCentralDirectory;
-
- /* This may be a problem with VERY large ZIPs! If the length of the */
- /* Central Directory exceeds 64K, this will NOT work! */
-
- Block = FileLen - Offset;
- free(Buffer);
-
- /* Read the entire Central Directory into memory and process each entry */
-
- Buffer = malloc( (size_t) Block);
- fseek(ZIPFile, S_Offset, SEEK_SET);
- fread(Buffer, (size_t) 1, (size_t) Block, ZIPFile);
- Printed = 0;
- for (Index = i = 0; i < Count; ++i) {
- ++S[ArcType][1];
- memmove(&CentralSig, &Buffer[Index], 4);
- if (CentralSig != CENTRAL_FILE_HEADER_SIGNATURE) {
- fprintf(stderr, "%s: Invalid ZIP format\n", Path);
- fprintf(stderr, " - bad \"Central Directory\" record!\n");
- free(Buffer);
- return;
- }
- Index += 4;
- CentralHeader = (CENTRAL_DIRECTORY_FILE_HEADER *) &Buffer[Index];
- Index += sizeof(CENTRAL_DIRECTORY_FILE_HEADER);
- Name = malloc(CentralHeader->FileNameLength + 1);
- memmove(Name, &Buffer[Index], CentralHeader->FileNameLength);
- Name[CentralHeader->FileNameLength] = '\0';
- Index += CentralHeader->FileNameLength
- + CentralHeader->FileCommentLength
- + CentralHeader->ExtraFieldLength;
- if ( (p = strrchr(Name, '/')) != NULL) {
- *p = '\0';
- strcpy(DireName, Name); strcat(DireName, "/");
- ++p;
- }
- else {
- DireName[0] = '\0';
- p = Name;
- }
- if ( SearchQ(p) ) {
- ++S[ArcType][2];
- ++TotalMatch;
- if (PageSwt) ChkPage();
- strcpy(V_Name, p);
- strcpy(V_Path, Path);
- if (CaseSwt == ON) {
- strlwr(V_Name);
- strlwr(V_Path);
- strlwr(DireName);
- }
- if (VerboseSwt) {
- if (!Printed) {
- if (!Spaced) {
- if (PageSwt) ChkPage();
- printf("\n");
- ++Lnno;
- }
- if (PageSwt) ChkPage();
- printf("%s\n", V_Path);
- ++Lnno;
- Printed = 1;
- }
- fputs("* ", stdout);
- PrtVerbose(DireName, V_Name, &CentralHeader->LastModFileTime,
- &CentralHeader->LastModFileDate,
- CentralHeader->UncompressedSize);
- }
- else printf("%s--> (%s/%s)\n", V_Path, DireName, V_Name);
- ++Lnno;
- }
- free(Name);
- }
- free(Buffer);
- if (Printed) {
- if (PageSwt) ChkPage();
- printf("\n");
- ++Lnno;
- Spaced = 1;
- }
- }